package com.learning.optimize.jdk.genericity;

import java.util.ArrayList;

/**
 * ClassName: GenericityRemove
 * Description: 泛型擦除
 * Date: 2018/7/25 11:21 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class GenericityRemove {

    public static void main(String[] args) throws Exception {
        test();
    }

    /**
     * 2-泛型的去类型化
     * <p>
     * 泛型是提供给javac编译器使用的， 但是编译器编译以后会去掉“类型信息”，使程序运行不受影响
     * 对于各个参数化的泛型类型，getClass()方法的返回值和原始类型完全一样。
     * <p>
     * 由于编译器生成的字节码会去掉泛型的类型信息，只要能跳过编译器，就可以往某个泛型
     * 集合中加入其它类型的数据：例如，用反射得到集合，再调用其add方法即可
     */
    static void test() throws Exception {

        // 两个不同泛型的集合，但是字节码是一样的
        ArrayList<String> list = new ArrayList<String>();
        ArrayList<Integer> list1 = new ArrayList<Integer>();
        //true 说明是同一份字节码
        System.out.println(list.getClass() == list1.getClass());

        // 往泛型为Integer的集合中放入String的值，编译肯定不过，但是可以利用反射跳过编译器，实现
//        list1.add("ababab");

        // 利用反射实现
        list1.getClass().getMethod("add", Object.class).invoke(list1, "现在就可以传字符串了");
        // 本来是 Integer 的类型,但是现在却成功加入了 String
        System.out.println(list1);

        // 编译器会返回Integer，实际应该是字符串了,编译正确，运行会报错
        Integer a = list1.get(0);
        System.out.println(list1.get(0));
        /*
        true
        [现在就可以传字符串了]
        Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
        */
    }
}
